//------------------------------------------------------------------------------
// <copyright file="Hero.cs" company="Damian Antonowicz">
//       copyright © 2010 Damian Antonowicz
// </copyright>
// <author>Damian Antonowicz</author>
// <email>poczta@damianantonowicz.pl</email>
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Xml.Serialization;
using System.Diagnostics;

namespace DotBeer.Business.Entities
{
    /// <summary>
    /// Contains informations about hero.
    /// </summary>
    public class Hero : AbstractHero
    {
        #region private properties

        string _author, _comments;

        DateTime lastUpdateDate;
        string dotaVersion;

        //items
        ObservableCollection<ItemBuild> _itemBuilds = new ObservableCollection<ItemBuild>();
        ObservableCollection<ItemHero> _currentItems = new ObservableCollection<ItemHero>();
        ItemBuild currentItemBuild;
        string _currentItemBuildName;

        //skills
        ObservableCollection<SkillBuild> _skillBuilds = new ObservableCollection<SkillBuild>();
        ObservableCollection<Skill> _currentSkills = new ObservableCollection<Skill>();
        SkillBuild _currentSkillBuild;
        string _currentSkillBuildName;
        const int maxNumberOfSkills = 25;
        bool canAddNewSkill = false;

        #endregion

        #region public properties

        public string DotaVersion
        {
            get 
            {
                if (string.IsNullOrEmpty(this.dotaVersion))
                    return "unknown";
                else
                    return this.dotaVersion; 
            }
            set { this.dotaVersion = value; }
        }

        public DateTime LastUpdateDate
        {
            get { return this.lastUpdateDate; }
            set { this.lastUpdateDate = value; }
        }

        public string Author
        {
            set
            {
                _author = value;
                OnPropertyChanged("Author");
            }
            get { return _author; }
        }

        public string Comments
        {
            set
            {
                _comments = value;
                OnPropertyChanged("Comments");
            }
            get { return _comments; }
        }

        public ObservableCollection<ItemBuild> ItemBuilds
        {
            get { return _itemBuilds; }
        }

        public int ItemBuildsCount
        {
            get { return _itemBuilds.Count; }
        }

        [XmlIgnore]
        public string[] ItemBuildsNames
        {
            get { return GetItemBuildsNames(); }
        }

        [XmlIgnore]
        public string CurrentItemBuildName
        {
            get { return _currentItemBuildName; }
            set
            {
                if (value != null)
                {
                    _currentItemBuildName = value;
                    SetCurrentItemBuild(value.ToString());
                    OnPropertyChanged("CurrentItemBuildName");
                }
            }
        }

        [XmlIgnore]
        public ItemBuild CurrentItemBuild
        {
            get { return this.currentItemBuild; }
            set
            {
                if (value != null)
                {
                    SetCurrentItemBuild(((ItemBuild)value).Name);
                    this.currentItemBuild = value;
                }
                else
                {
                    _currentItems.Clear();
                    this.currentItemBuild = null;
                }

                this.OnPropertyChanged("CurrentItemBuild");
            }
        }

        [XmlIgnore]
        public IList<ItemHero> CurrentItems
        {
            get { return _currentItems; }
        }

        public ObservableCollection<SkillBuild> SkillBuilds
        {
            get { return _skillBuilds; }
        }

        [XmlIgnore]
        public SkillBuild CurrentSkillBuild
        {
            get { return this._currentSkillBuild; }
            set
            {
                if (value != null)
                {
                    _currentSkillBuild = value;
                    SetCurrentSkillBuild(((SkillBuild)value).Name);
                }
                else
                {
                    _currentSkills.Clear();
                    _currentSkillBuild = null;
                }
            }
        }

        [XmlIgnore]
        public int MaxNumberOfSkills
        {
            get { return maxNumberOfSkills; }
        }

        [XmlIgnore]
        public bool CanAddNewSkill
        {
            get { return this.canAddNewSkill; }
        }

        [XmlIgnore]
        public string[] SkillBuildsNames
        {
            get { return GetSkillBuildsNames(); }
        }

        [XmlIgnore]
        public string CurrentSkillBuildName
        {
            get { return _currentSkillBuildName; }
            set
            {
                if (value != null)
                {
                    _currentSkillBuildName = value;
                    SetCurrentSkillBuild(value.ToString());
                    OnPropertyChanged("CurrentSkillBuildName");
                }
            }
        }

        [XmlIgnore]
        public ObservableCollection<Skill> CurrentSkills
        {
            get { return _currentSkills; }
        }

        #endregion

        #region constructor

        public Hero()
        {
            _itemBuilds.CollectionChanged += new NotifyCollectionChangedEventHandler(_itemBuilds_CollectionChanged);
            _skillBuilds.CollectionChanged += new NotifyCollectionChangedEventHandler(_skillBuilds_CollectionChanged);
        }

        #endregion

        #region public methods

        public void Clear()
        {
            _author = "";
            _comments = "";
            _itemBuilds.Clear();
            _currentItems.Clear();
            _currentItemBuildName = "";
            _skillBuilds.Clear();
            _currentSkills.Clear();
            _currentSkillBuildName = "";

            OnPropertyChanged("Author");
            OnPropertyChanged("Comments");
            OnPropertyChanged("ItemBuilds");
            OnPropertyChanged("CurrentItemBuildName");
            OnPropertyChanged("SkillBuilds");
            OnPropertyChanged("CurrentSkills");
            OnPropertyChanged("CurrentItems");
            OnPropertyChanged("CurrentSkillsBuildName");
        }

        public void AddNewItemBuild()
        {
            string itemBuildName = "ItemBuild";
            itemBuildName += (_itemBuilds.Where(b => b.Name.Contains(itemBuildName)).Count() + 1).ToString();
            _itemBuilds.Add(new ItemBuild() { Name = itemBuildName });
        }

        public void AddNewSkillBuild()
        {
            string skillBuildName = "SkillBuild";
            skillBuildName += (_skillBuilds.Where(b => b.Name.Contains(skillBuildName)).Count() + 1).ToString();
            _skillBuilds.Add(new SkillBuild() { Name = skillBuildName });
        }

        #endregion

        #region private methods

        private string[] GetItemBuildsNames()
        {
            string[] names = _itemBuilds.Select(b => b.Name).ToArray();

            if (names.Length > 0)
                CurrentItemBuildName = names[0];

            return names;
        }

        private string[] GetSkillBuildsNames()
        {
            string[] names = _skillBuilds.Select(b => b.Name).ToArray();

            if (names.Length > 0)
                CurrentSkillBuildName = names[0];

            return names;
        }

        private void SetCurrentItemBuild(string name)
        {
            _currentItems = _itemBuilds.Where(b => b.Name == name).Select(b => b.Items).SingleOrDefault();

            if (_currentItems != null)
            {
                OnPropertyChanged("CurrentItems");
            }
        }

        private void SetCurrentSkillBuild(string name)
        {
            if (_currentSkills != null)
                _currentSkills.CollectionChanged -= _currentSkills_CollectionChanged;

            _currentSkills = _skillBuilds.Where(b => b.Name == name).Select(b => b.Skills).SingleOrDefault();

            if (_currentSkills != null)
            {
                _currentSkills.CollectionChanged += new NotifyCollectionChangedEventHandler(_currentSkills_CollectionChanged);
                OnPropertyChanged("CurrentSkills");
            }
        }

        private void _skillBuilds_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
                _skillBuilds[e.NewStartingIndex].PropertyChanged += new PropertyChangedEventHandler(skillBuild_PropertyChanged);
        }

        private void _itemBuilds_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
                _itemBuilds[e.NewStartingIndex].PropertyChanged += new PropertyChangedEventHandler(itemBuild_PropertyChanged);
        }

        private void itemBuild_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Name")
            {
                ItemBuild build = (ItemBuild)sender;

                if (_itemBuilds.Where(b => b.Name == build.Name).Count() > 1)
                    build.RestoreOldName();
            }
        }

        private void skillBuild_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Name")
            {
                SkillBuild build = (SkillBuild)sender;

                if (_skillBuilds.Where(b => b.Name == build.Name).Count() > 1)
                    build.RestoreOldName();
            }
        }

        private void _currentSkills_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            ReNumerateSkills();
        }

        private void ReNumerateSkills()
        {
            int counter = 1;

            foreach (Skill skill in _currentSkills)
                skill.Level = counter++.ToString();
        }

        #endregion
    }
}
